﻿Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Data
Imports System.Windows.Forms

Namespace KnobControl

    ' A delegate type for hooking up ValueChanged notifications. 
    Public Delegate Sub ValueChangedEventHandler(ByVal Sender As Object)

    ''' <summary>
    ''' Summary description for KnobControl.
    ''' </summary>
    <System.ComponentModel.DefaultEvent("ValueChanged")> Public Class KnobControl
        Inherits System.Windows.Forms.UserControl
        ''' <summary> 
        ''' Required designer variable.
        ''' </summary>
        Private components As System.ComponentModel.Container = Nothing

        Private _Minimum As Integer = 0
        Private _Maximum As Integer = 100
        Private _LargeChange As Integer = 10
        Private _SmallChange As Integer = 1
        Private _ShowSmallScale As Boolean = False
        Private _ShowLargeScale As Boolean = True
        Private _isFocused As Boolean = False
        Private ConColor As Color = Color.Gray

        Private _Value As Integer = 0
        Private isKnobRotating As Boolean = False
        Private rKnob As Rectangle
        Private pKnob As Point
        Private rScale As Rectangle
        Private DottedPen As Pen

        Private bKnob As Brush
        Private bKnobPoint As Brush

        Private M_PointCol As Color = Color.DodgerBlue
        Private M_KnobCol As Color = Color.FromArgb(65, 65, 65)
        Private M_Border As Integer = 10
        Private M_Gradient As Integer = 120
        Private M_PointSize As Integer = 6
        Private M_SpanDeg As Integer = 270
        Private M_StartDeg As Integer = 135
        Private M_PtoP As Integer = 2
        Private M_digitSize As Integer = 15
        Private M_digitcount As Integer = 4
        Private M_digitColor As Color = Color.GreenYellow
        Private M_DigitColorFollowPointColor As Boolean = True
        Private M_digitsVisible As Boolean = True
        Private M_digitBorder As Integer = 2
        Private M_Max As Integer = 100
        Private M_Min As Integer = 0
        Private M_Value As Integer = 0
        Private M_Change As Integer = 10
        Private M_usePersent As Boolean = False
        Private M_PMax As Double = 1
        Private M_PMin As Double = 0
        Private M_PVal As Double = 0
        '-------------------------------------------------------
        ' declare Off screen image and Offscreen graphics       
        '-------------------------------------------------------
        Private OffScreenImage As Image
        Private gOffScreen As Graphics
        '-------------------------------------------------------
        ' An event that clients can use to be notified whenever 
        ' the Value is Changed.                                 
        '-------------------------------------------------------
        Public Event ValueChanged As ValueChangedEventHandler
        '-------------------------------------------------------
        ' Invoke the ValueChanged event; called  when value     
        ' is changed                                            
        '-------------------------------------------------------
        Protected Overridable Sub OnValueChanged(ByVal sender As Object)
            RaiseEvent ValueChanged(sender)
        End Sub
        Public Property ShowSmallScale() As Boolean
            Get
                Return _ShowSmallScale
            End Get
            Set(ByVal value As Boolean)
                _ShowSmallScale = value
                Refresh()
            End Set
        End Property
        Public Property ShowLargeScale() As Boolean
            Get
                Return _ShowLargeScale
            End Get
            Set(ByVal value As Boolean)
                _ShowLargeScale = value
                Refresh()
            End Set
        End Property
        Public Property Minimum() As Double
            Get
                If M_usePersent = False Then
                    Return M_Min
                Else
                    Return M_PMin
                End If
            End Get
            Set(ByVal value As Double)

                If M_usePersent = False Then
                    If value > M_Max Then value = 0
                    M_PMin = value
                    M_Min = value
                    _Minimum = 0
                    _Maximum = M_Max - M_Min
                    _Value = _Minimum
                    setDimensions()
                    Refresh()
                Else
                    If value > M_PMax Then value = 0
                    M_PMin = value
                    _Minimum = 0
                    _Maximum = 100
                    _Value = 0
                    setDimensions()
                    Refresh()
                End If
            End Set
        End Property
        Public Property Maximum() As Double
            Get
                If M_usePersent = False Then
                    Return M_Max
                Else
                    Return M_PMax
                End If
            End Get
            Set(ByVal value As Double)
                If M_usePersent = False Then
                    M_Max = value
                    M_PMax = value
                    _Minimum = 0
                    _Maximum = M_Max - M_Min
                    _Value = _Minimum
                    setDimensions()
                    Refresh()
                Else
                    M_PMax = value
                    _Minimum = 0
                    _Maximum = 100
                    _Value = 0
                    setDimensions()
                    Refresh()
                End If
            End Set
        End Property
        Public Property LargeChange() As Integer
            Get
                Return _LargeChange
            End Get
            Set(ByVal value As Integer)
                _LargeChange = value
                Refresh()
            End Set
        End Property
        Public Property SmallChange() As Integer
            Get
                Return _SmallChange
            End Get
            Set(ByVal value As Integer)
                _SmallChange = value
                Refresh()
            End Set
        End Property
        Public Property IntegerValue() As Integer
            Get
                If M_usePersent = False Then
                    Return _Value + M_Min
                Else
                    Return 0
                End If
            End Get
            Set(ByVal value As Integer)
                If M_usePersent = False Then
                    _Value = value - M_Min
                    Refresh()
                    OnValueChanged(Me)
                End If
            End Set
        End Property
        Public Property PersentValue() As Double
            Get
                Return _Value
            End Get
            Set(ByVal value As Double)
                If M_usePersent = True Then
                    _Value = value
                End If
                Refresh()
            End Set
        End Property
        Public Property Value() As Double
            Get
                If M_usePersent = False Then
                    Return IntegerValue
                Else
                    M_PVal = M_PMin + ((M_PMax - M_PMin) * (_Value / 100))
                    Return M_PVal
                End If
            End Get
            Set(ByVal value As Double)
                If M_usePersent = False Then
                    _Value = value - M_Min
                    setDimensions()
                    Refresh()
                Else
                    _Value = (value / (M_PMax - M_PMin)) * 100
                    setDimensions()
                    Refresh()
                End If
            End Set
        End Property
        Public Property UsePersentage() As Boolean
            Get
                Return M_usePersent
            End Get
            Set(ByVal value As Boolean)
                M_usePersent = value
                setDimensions()
                Refresh()
            End Set
        End Property
        Public Property DigitSize() As Integer
            Get
                Return M_digitSize
            End Get
            Set(ByVal value As Integer)
                M_digitSize = value
                'setDimensions()
                Refresh()
            End Set
        End Property
        Public Property DigitCount() As Integer
            Get
                Return M_digitcount
            End Get
            Set(ByVal value As Integer)
                M_digitcount = value
                'setDimensions()
                Refresh()
            End Set
        End Property

        Public Property DigitColor() As Color
            Get
                Return M_digitColor
            End Get
            Set(ByVal value As Color)
                M_digitColor = value
                'setDimensions()
                Refresh()
            End Set
        End Property
        Public Property DigitFollowPointColor() As Boolean
            Get
                Return M_DigitColorFollowPointColor
            End Get
            Set(ByVal value As Boolean)
                M_DigitColorFollowPointColor = value
                Refresh()
            End Set
        End Property
        Public Property DigitsVisible() As Boolean
            Get
                Return M_digitsVisible
            End Get
            Set(ByVal value As Boolean)
                M_digitsVisible = value
                Refresh()
            End Set
        End Property
        Public Property DigitBorder() As Integer
            Get
                Return M_digitBorder
            End Get
            Set(ByVal value As Integer)
                M_digitBorder = value
                Refresh()
            End Set
        End Property
        Public Property minmax() As String
            Get
                Return _Minimum.ToString & " : " & _Maximum.ToString
            End Get
            Set(ByVal value As String)

            End Set
        End Property
        Public Property MouseWheelChange() As Integer
            Get
                Return M_Change
            End Get
            Set(ByVal value As Integer)
                M_Change = value
            End Set
        End Property
        Public Sub New()

            ' This call is required by the Windows.Forms Form Designer.
            DottedPen = New Pen(Utility.getDarkColor(Me.BackColor, 40))
            DottedPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash
            DottedPen.DashCap = System.Drawing.Drawing2D.DashCap.Flat

            InitializeComponent()


            ' TODO: Add any initialization after the InitForm call

            setDimensions()
        End Sub
        Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias
            Dim g As Graphics = e.Graphics
            gOffScreen.Clear(ConColor)
            gOffScreen.FillEllipse(bKnob, rKnob)
            gOffScreen.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias
            gOffScreen.DrawEllipse(New Pen(ConColor), rKnob)

            If Me._isFocused Then
                Dim P As New Pen(M_PointCol, 3)
                Dim R As New Rectangle(rKnob.X + 2, rKnob.Y + 2, rKnob.Width - 4, rKnob.Height - 4)
                gOffScreen.DrawEllipse(P, R)
            End If

            Dim Arrow As Point = Me.getKnobPosition()
            gOffScreen.FillEllipse(New SolidBrush(M_PointCol), New Rectangle(Arrow.X - (M_PointSize / 2), Arrow.Y - (M_PointSize / 2), M_PointSize, M_PointSize))
            gOffScreen.DrawEllipse(Pens.Black, New Rectangle(Arrow.X - (M_PointSize / 2), Arrow.Y - (M_PointSize / 2), M_PointSize, M_PointSize))
            If Me._ShowSmallScale Then
                Dim i As Integer = _Minimum
                While i <= _Maximum
                    gOffScreen.DrawLine(New Pen(Me.ForeColor), getMarkerPoint(0, i), getMarkerPoint(3, i))
                    i += Me._SmallChange
                End While
            End If
            If Me._ShowLargeScale Then
                Dim i As Integer = _Minimum
                While i <= _Maximum
                    gOffScreen.DrawLine(New Pen(Me.ForeColor), getMarkerPoint(0, i), getMarkerPoint(5, i))
                    i += Me._LargeChange
                End While
            End If

            'drawdigit
            If M_digitsVisible = True Then
                Dim sevenSegmentHelper As New SevenSegmentHelper(gOffScreen)
                Dim digitcount As String = "8"
                digitcount = digitcount.PadLeft(M_digitcount, "8")
                Dim digitSizeF As SizeF = sevenSegmentHelper.GetStringSize(digitcount, Font)
                Dim scaleFactor As Single = Math.Min(ClientSize.Width / digitSizeF.Width, M_digitSize / digitSizeF.Height)
                Dim font__1 As New Font(Font.FontFamily, scaleFactor * Font.SizeInPoints)
                digitSizeF = sevenSegmentHelper.GetStringSize(digitcount, font__1)
                gOffScreen.FillRectangle(Brushes.Black, ((ClientSize.Width - digitSizeF.Width) / 2) - M_digitBorder, ((ClientSize.Height - digitSizeF.Height) / 2) - M_digitBorder, digitSizeF.Width + (M_digitBorder * 2), digitSizeF.Height + (M_digitBorder * 2))
                If M_usePersent = False Then
                    If M_DigitColorFollowPointColor = True Then
                        Using brush As New SolidBrush(M_PointCol)
                            Using lightBrush As New SolidBrush(Color.FromArgb(20, M_PointCol))
                                sevenSegmentHelper.DrawDigits(IntegerValue.ToString, font__1, brush, lightBrush, (ClientSize.Width - digitSizeF.Width) / 2, (ClientSize.Height - digitSizeF.Height) / 2, M_digitcount)
                            End Using
                        End Using
                    Else
                        Using brush As New SolidBrush(M_digitColor)
                            Using lightBrush As New SolidBrush(Color.FromArgb(20, M_digitColor))
                                sevenSegmentHelper.DrawDigits(IntegerValue.ToString, font__1, brush, lightBrush, (ClientSize.Width - digitSizeF.Width) / 2, (ClientSize.Height - digitSizeF.Height) / 2, M_digitcount)
                            End Using
                        End Using
                    End If
                Else
                    If M_DigitColorFollowPointColor = True Then
                        Using brush As New SolidBrush(M_PointCol)
                            Using lightBrush As New SolidBrush(Color.FromArgb(20, M_PointCol))
                                sevenSegmentHelper.DrawDigits(_Value.ToString, font__1, brush, lightBrush, (ClientSize.Width - digitSizeF.Width) / 2, (ClientSize.Height - digitSizeF.Height) / 2, M_digitcount)
                            End Using
                        End Using
                    Else
                        Using brush As New SolidBrush(M_digitColor)
                            Using lightBrush As New SolidBrush(Color.FromArgb(20, M_digitColor))
                                sevenSegmentHelper.DrawDigits(_Value.ToString, font__1, brush, lightBrush, (ClientSize.Width - digitSizeF.Width) / 2, (ClientSize.Height - digitSizeF.Height) / 2, M_digitcount)
                            End Using
                        End Using
                    End If
                End If

            End If
            ' Drawimage on screen  
            g.Clear(ConColor)
            g.DrawImage(OffScreenImage, 0, 0)
        End Sub

        Protected Overrides Sub OnPaintBackground(ByVal e As PaintEventArgs)
            ' Empty To avoid Flickring due do background Drawing.
        End Sub
        Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
            If Utility.isPointinRectangle(New Point(e.X, e.Y), rKnob) Then
                If e.Button = Windows.Forms.MouseButtons.Left Then
                    ' Start Rotation of knob         
                    Me.isKnobRotating = True
                End If
                If e.Button = Windows.Forms.MouseButtons.Right Then

                End If
            End If

        End Sub

        '----------------------------------------------------------
        ' we need to override IsInputKey method to allow user to   
        ' use up, down, right and bottom keys other wise using this
        ' keys will change focus from current object to another    
        ' object on the form                                       
        '----------------------------------------------------------
        Protected Overrides Function IsInputKey(ByVal key As Keys) As Boolean
            Select Case key
                Case Keys.Up, Keys.Down, Keys.Right, Keys.Left
                    Return True
            End Select
            Return MyBase.IsInputKey(key)
        End Function

        Protected Overrides Sub OnMouseUp(ByVal e As MouseEventArgs)
            ' Stop rotation                   
            Me.isKnobRotating = False
            If Utility.isPointinRectangle(New Point(e.X, e.Y), rKnob) Then
                ' get value                   
                Me._Value = Me.getValueFromPosition(New Point(e.X, e.Y))
                RaiseEvent ValueChanged(Me)
            End If
            Me.Cursor = Cursors.[Default]
        End Sub

        Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
            '--------------------------------------
            '  Following Handles Knob Rotating     
            '--------------------------------------
            If Me.isKnobRotating = True Then
                Me.Cursor = Cursors.Hand
                Dim p As New Point(e.X, e.Y)
                Dim posVal As Integer = Me.getValueFromPosition(p)
                _Value = posVal
                Refresh()
                'RaiseEvent ValueChanged(Me)
            End If

        End Sub
        Protected Overrides Sub OnKeyDown(ByVal e As KeyEventArgs)

            '--------------------------------------------------------
            ' Handles knob rotation with up,down,left and right keys 
            '--------------------------------------------------------
            If e.KeyCode = Keys.Up OrElse e.KeyCode = Keys.Right Then
                If _Value < Maximum Then
                    IntegerValue = _Value + 1
                End If
                Me.Refresh()
                RaiseEvent ValueChanged(Me)
            ElseIf e.KeyCode = Keys.Down OrElse e.KeyCode = Keys.Left Then
                If _Value > Minimum Then
                    IntegerValue = _Value - 1
                End If
                Me.Refresh()
                RaiseEvent ValueChanged(Me)
            End If
        End Sub
        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            If disposing Then
                If components IsNot Nothing Then
                    components.Dispose()
                End If
            End If
            MyBase.Dispose(disposing)
        End Sub

#Region "Component Designer generated code"
        ''' <summary> 
        ''' Required method for Designer support - do not modify 
        ''' the contents of this method with the code editor.
        ''' </summary>
        Private Sub InitializeComponent()
            Me.SuspendLayout()
            '
            'KnobControl
            '
            Me.BackColor = System.Drawing.Color.Transparent
            Me.ImeMode = System.Windows.Forms.ImeMode.[On]
            Me.Name = "KnobControl"
            Me.ResumeLayout(False)

        End Sub
#End Region
        Private Sub setDimensions()
            ' get smaller from height and width
            Dim size As Integer = Me.Width
            If Me.Width > Me.Height Then
                size = Me.Height
            End If
            size = size
            ' allow 10% gap on all side to determine size of knob    
            'Me.rKnob = New Rectangle(CInt(Math.Truncate(size * 0.2)), CInt(Math.Truncate(size * 0.2)), CInt(Math.Truncate(size * 0.6)), CInt(Math.Truncate(size * 0.6)))
            Me.rKnob = New Rectangle(M_Border, M_Border, (size - (M_Border * 2)), (size - (M_Border * 2)))

            Me.rScale = New Rectangle(2, 2, size - 4, size - 4)

            Me.pKnob = New Point(rKnob.X + rKnob.Width \ 2, rKnob.Y + rKnob.Height \ 2)
            ' create offscreen image                                 
            Me.OffScreenImage = New Bitmap(Me.Width, Me.Height)
            ' create offscreen graphics                              
            Me.gOffScreen = Graphics.FromImage(OffScreenImage)

            ' create LinearGradientBrush for creating knob            
            bKnob = New System.Drawing.Drawing2D.LinearGradientBrush(rKnob, Utility.getLightColor(M_KnobCol, M_Gradient), Utility.getDarkColor(M_KnobCol, M_Gradient), LinearGradientMode.ForwardDiagonal)
            ' create LinearGradientBrush for knobPoint                
            bKnobPoint = New System.Drawing.Drawing2D.LinearGradientBrush(rKnob, Utility.getLightColor(M_PointCol, 55), Utility.getDarkColor(M_PointCol, 55), LinearGradientMode.ForwardDiagonal)
        End Sub
        Public Property PointSize() As Integer
            Get
                Return M_PointSize
            End Get
            Set(ByVal value As Integer)
                M_PointSize = value
                Refresh()
            End Set
        End Property
        Public Property GradientDifference() As Integer
            Get
                Return M_Gradient
            End Get
            Set(ByVal value As Integer)
                M_Gradient = value
                setDimensions()
                Refresh()
            End Set
        End Property
        Public Property BorderSpace() As Integer
            Get
                Return M_Border
            End Get
            Set(ByVal value As Integer)
                M_Border = value
                setDimensions()
                Refresh()
            End Set
        End Property
        ''' <summary>
        ''' Color Of knob
        ''' </summary>
        Public Property KnobColor() As Color
            Get
                Return M_KnobCol
            End Get
            Set(ByVal value As Color)
                M_KnobCol = value
                setDimensions()
                Refresh()
            End Set
        End Property
        Public Property PointColor() As Color
            Get
                Return M_PointCol
            End Get
            Set(ByVal value As Color)
                M_PointCol = value
                setDimensions()
                Refresh()
            End Set
        End Property
        Public Property PointToBorder() As Integer
            Get
                Return M_PtoP
            End Get
            Set(ByVal value As Integer)
                M_PtoP = value
                setDimensions()
                Refresh()
            End Set
        End Property

        Private Sub KnobControl_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Resize
            setDimensions()
            Refresh()
        End Sub
        Public Property ContainerColor() As Color
            Get
                Return ConColor
            End Get
            Set(ByVal value As Color)
                ConColor = value
                Refresh()
            End Set
        End Property
        Private Function getKnobPosition() As Point
            Dim degree As Double = M_SpanDeg * _Value \ (Me._Maximum - Me._Minimum) '270
            degree = (degree + M_StartDeg) * Math.PI / 180 '135

            Dim Pos As New Point(0, 0)
            Pos.X = CInt(Math.Truncate(Math.Cos(degree) * (rKnob.Width \ 2 - (M_PtoP + 4)) + rKnob.X + rKnob.Width \ 2))
            Pos.Y = CInt(Math.Truncate(Math.Sin(degree) * (rKnob.Width \ 2 - (M_PtoP + 4)) + rKnob.Y + rKnob.Height \ 2))
            Return Pos
        End Function
        Private Function getMarkerPoint(ByVal length As Integer, ByVal Value As Integer) As Point
            Dim degree As Double = M_SpanDeg * Value \ (Me._Maximum - Me._Minimum)
            degree = (degree + M_StartDeg) * Math.PI / 180

            Dim Pos As New Point(0, 0)
            Pos.X = CInt(Math.Truncate(Math.Cos(degree) * (rKnob.Width \ 2 - length + 7) + rKnob.X + rKnob.Width \ 2))
            Pos.Y = CInt(Math.Truncate(Math.Sin(degree) * (rKnob.Width \ 2 - length + 7) + rKnob.Y + rKnob.Height \ 2))
            Return Pos
        End Function
        Private Function getValueFromPosition(ByVal p As Point) As Integer
            Dim degree As Double = 0.0
            Dim v As Integer = 0
            If p.X <= pKnob.X Then
                degree = CDbl(pKnob.Y - p.Y) / CDbl(pKnob.X - p.X)
                degree = Math.Atan(degree)
                degree = (degree) * (180 / Math.PI) + 45

                v = CInt(Math.Truncate(degree * (Me._Maximum - Me._Minimum) / 270))
            ElseIf p.X > pKnob.X Then
                degree = CDbl(p.Y - pKnob.Y) / CDbl(p.X - pKnob.X)
                degree = Math.Atan(degree)
                degree = 225 + (degree) * (180 / Math.PI)

                v = CInt(Math.Truncate(degree * (Me.Maximum - Me.Minimum) / 270))
            End If
            If v > _Maximum Then
                v = _Maximum
            End If
            If v < _Minimum Then
                v = _Minimum
            End If
            Return v

        End Function
        Public Property SpanDegrees() As Integer
            Get
                Return M_SpanDeg
            End Get
            Set(ByVal value As Integer)
                M_SpanDeg = value
                setDimensions()
                Refresh()
            End Set
        End Property
        Public Property StartDegrees() As Integer
            Get
                Return M_StartDeg
            End Get
            Set(ByVal value As Integer)
                M_StartDeg = value
                setDimensions()
                Refresh()
            End Set
        End Property
        Private Sub KnobControl_MouseEnter(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.MouseEnter
            Me.Select()
            Me._isFocused = True
            Refresh()
        End Sub

        Private Sub KnobControl_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.MouseLeave
            Me._isFocused = False
            Refresh()
        End Sub

        Private Sub KnobControl_MouseWheel(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseWheel
            If _isFocused = True Then
                If e.Delta > 0 Then
                    _Value = _Value + M_Change
                Else
                    _Value = _Value - M_Change
                End If
                If _Value > _Maximum Then _Value = _Maximum
                If _Value < _Minimum Then _Value = _Minimum
                Refresh()
                RaiseEvent ValueChanged(Me)
            End If
        End Sub
        Public Sub UpdateKnob()
            setDimensions()
            Refresh()
        End Sub

        Private Sub KnobControl_VisibleChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.VisibleChanged
            Me.Refresh()
        End Sub
    End Class

    Public Class SevenSegmentHelper
        Private _graphics As Graphics

        ' Indicates what segments are illuminated for all 10 digits
        Shared _segmentData As Byte(,) = {{1, 1, 1, 0, 1, 1, 1}, _
        {0, 0, 1, 0, 0, 1, 0}, {1, 0, 1, 1, 1, 0, 1}, {1, 0, 1, 1, 0, 1, 1}, {0, 1, 1, 1, 0, 1, 0}, _
        {1, 1, 0, 1, 0, 1, 1}, {1, 1, 0, 1, 1, 1, 1}, {1, 0, 1, 0, 0, 1, 0}, {1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 0, 1, 1}, {0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}}

        ' Points that define each of the seven segments
        ReadOnly _segmentPoints As Point()() = New Point(6)() {}

        Public Sub New(ByVal graphics As Graphics)
            Me._graphics = graphics
            _segmentPoints(0) = New Point() {New Point(3, 2), New Point(39, 2), New Point(31, 10), New Point(11, 10)}
            _segmentPoints(1) = New Point() {New Point(2, 3), New Point(10, 11), New Point(10, 31), New Point(2, 35)}
            _segmentPoints(2) = New Point() {New Point(40, 3), New Point(40, 35), New Point(32, 31), New Point(32, 11)}
            _segmentPoints(3) = New Point() {New Point(3, 36), New Point(11, 32), New Point(31, 32), New Point(39, 36), New Point(31, 40), New Point(11, 40)}
            _segmentPoints(4) = New Point() {New Point(2, 37), New Point(10, 41), New Point(10, 61), New Point(2, 69)}
            _segmentPoints(5) = New Point() {New Point(40, 37), New Point(40, 69), New Point(32, 61), New Point(32, 41)}
            _segmentPoints(6) = New Point() {New Point(11, 62), New Point(31, 62), New Point(39, 70), New Point(3, 70)}
        End Sub

        Public Function GetStringSize(ByVal text As String, ByVal font As Font) As SizeF
            Dim sizef As New SizeF(0, _graphics.DpiX * font.SizeInPoints / 72)

            For i As Integer = 0 To text.Length - 1
                If [Char].IsDigit(text(i)) Then
                    sizef.Width += 42 * _graphics.DpiX * font.SizeInPoints / 72 / 72
                ElseIf text(i) = ":"c OrElse text(i) = "."c Then
                    sizef.Width += 12 * _graphics.DpiX * font.SizeInPoints / 72 / 72
                End If
            Next
            Return sizef
        End Function

        Public Sub DrawDigits(ByVal text As String, ByVal font As Font, ByVal brush As Brush, ByVal brushLight As Brush, ByVal x As Single, ByVal y As Single, ByVal l As Integer)
            text = text.PadLeft(l, "*")
            For cnt As Integer = 0 To text.Length - 1
                ' For digits 0-9
                If [Char].IsDigit(text(cnt)) Then
                    x = DrawDigit(Asc(text(cnt)) - Asc("0"), font, brush, brushLight, x, y)
                    ' For colon :
                ElseIf text(cnt) = ":"c Then
                    x = DrawColon(font, brush, x, y)
                    ' For dot .
                ElseIf text(cnt) = "."c Then
                    x = DrawDot(font, brush, x, y)
                ElseIf text(cnt) = "-"c Then
                    x = DrawDigit(10, font, brush, brushLight, x, y)
                ElseIf text(cnt) = "*"c Then
                    x = DrawDigit(11, font, brush, brushLight, x, y)
                End If
            Next
        End Sub

        Private Function DrawDigit(ByVal num As Integer, ByVal font As Font, ByVal brush As Brush, ByVal brushLight As Brush, ByVal x As Single, ByVal y As Single) As Single
            For cnt As Integer = 0 To _segmentPoints.Length - 1
                If _segmentData(num, cnt) = 1 Then
                    FillPolygon(_segmentPoints(cnt), font, brush, x, y)
                Else
                    FillPolygon(_segmentPoints(cnt), font, brushLight, x, y)
                End If
            Next
            Return x + 42 * _graphics.DpiX * font.SizeInPoints / 72 / 72
        End Function

        Private Function DrawDot(ByVal font As Font, ByVal brush As Brush, ByVal x As Single, ByVal y As Single) As Single
            Dim dotPoints As Point()() = New Point(0)() {}

            dotPoints(0) = New Point() {New Point(2, 64), New Point(6, 61), New Point(10, 64), New Point(6, 69)}

            For cnt As Integer = 0 To dotPoints.Length - 1
                FillPolygon(dotPoints(cnt), font, brush, x, y)
            Next
            Return x + 12 * _graphics.DpiX * font.SizeInPoints / 72 / 72
        End Function

        Private Function DrawColon(ByVal font As Font, ByVal brush As Brush, ByVal x As Single, ByVal y As Single) As Single
            Dim colonPoints As Point()() = New Point(1)() {}

            colonPoints(0) = New Point() {New Point(2, 21), New Point(6, 17), New Point(10, 21), New Point(6, 25)}
            colonPoints(1) = New Point() {New Point(2, 51), New Point(6, 47), New Point(10, 51), New Point(6, 55)}

            For cnt As Integer = 0 To colonPoints.Length - 1
                FillPolygon(colonPoints(cnt), font, brush, x, y)
            Next
            Return x + 12 * _graphics.DpiX * font.SizeInPoints / 72 / 72
        End Function

        Private Sub FillPolygon(ByVal polygonPoints As Point(), ByVal font As Font, ByVal brush As Brush, ByVal x As Single, ByVal y As Single)
            Dim polygonPointsF As PointF() = New PointF(polygonPoints.Length - 1) {}

            For cnt As Integer = 0 To polygonPoints.Length - 1
                polygonPointsF(cnt).X = x + polygonPoints(cnt).X * _graphics.DpiX * font.SizeInPoints / 72 / 72
                polygonPointsF(cnt).Y = y + polygonPoints(cnt).Y * _graphics.DpiY * font.SizeInPoints / 72 / 72
            Next
            _graphics.FillPolygon(brush, polygonPointsF)
        End Sub
    End Class
End Namespace
